#ifndef TRIANGLE_H_
#define TRIANGLE_H_

#include "constants.h"
#include "Point.h"
#include "Vertex.h"
#include "Material.h"

struct TriAccel
{
  // first 16 byte half cache line
  // plane:
  float n_u; //!< == normal.u / normal.k
  float n_v; //!< == normal.v / normal.k
  float n_d; //!< constant of plane equation
  int k;     // projection dimension
  // second 16 byte half cache line
  // line equation for line ac
  float b_nu;
  float b_nv;
  float b_d;
//  int pad; // pad to next cache line
  float u; // first barycentric coordinate
  // third 16 byte half cache line
  // line equation for line ab
  float c_nu;
  float c_nv;
  float c_d;
//  int pad2; // pad to 48 bytes for cache alignment purposes
  float v; // second barycentric coordinate
};


class Triangle
{
public:
	Triangle();
	Triangle(const Vertex* p[3], const Material* m);
	~Triangle();

	TriAccel triAccel;
	const Vertex* vertices[3];
	Vector normal;
	const Material* material;

	/**
	 * 0 <= i < 3
	 */
	const SPoint& getPoint(const int i) const
	{
		return vertices[i]->getPoint();
	}
	
	/**
	 * 0 <= i < 3
	 */
	const Vector& getNormal(const int i) const
	{
		return vertices[i]->getNormal();
	}
	
	/**
		 * 0 <= i < 3
		 */
	const Vertex* getVertex(const int i) const
	{
		return vertices[i];
	}
	
	Vector getNormal(const SPoint& hit) const;
	
	void precalculate(const SPoint& viewPoint);

	float getMin(const int axis) const
	{
		return std::min(std::min(vertices[0]->getPoint().get(axis), vertices[1]->getPoint().get(axis)), vertices[2]->getPoint().get(axis));
	}
	float getMax(const int axis) const
	{
		return std::max(std::max(vertices[0]->getPoint().get(axis), vertices[1]->getPoint().get(axis)), vertices[2]->getPoint().get(axis));
	}
private:
	Triangle(const Triangle& copy) : normal(copy.normal)
	{
	}
};

#endif /*TRIANGLE_H_*/
